import json

from django.db.models.functions import TruncDate
from django.shortcuts import render
from rest_framework import viewsets
from rest_framework.views import APIView
from .serializers import OrderSerializer
from rest_framework.response import Response
from rest_framework import status
from .models import Order
from django.utils import timezone
from datetime import timedelta, datetime
from django.db.models import Count, F, Sum, Min, Max
from collections import OrderedDict
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf  # 自相关图、偏自相关图
from statsmodels.tsa.stattools import adfuller as ADF  # 平稳性检验
from statsmodels.stats.diagnostic import acorr_ljungbox  # 白噪声检验
import statsmodels.tsa.stattools as st
import statsmodels.api as sm  # D-W检验,一阶自相关检验
from statsmodels.graphics.api import qqplot  # 画QQ图,检验一组数据是否服从正态分布
from statsmodels.tsa.arima.model import ARIMA


# 读取数据
def myprint():
    print("aaaaaaaaaa")


def yuce(daylong, total_list):
    data = total_list
    print(data)
    length = len(total_list)
    # 差分检验
    d = 0
    result = ADF(data)
    while result[1] > 0.05:
        d_sale = data.diff(periods=1).dropna()  # dropna删除NaN
        result = ADF(d_sale)
        d = d + 1
    # 白噪声检验
    # result = acorr_ljungbox(data,lags=1)
    # if result.lb_pvalue.values[0]<0.05:
    #     return 0
    # else:
    #     print(result.lb_pvalue.values[0])

    # 定阶
    # order_analyze = st.arma_order_select_ic(data, max_ar=9, max_ma=9, ic=['bic'])
    # p = order_analyze.bic_min_order[0]
    # q = order_analyze.bic_min_order[1]
    p = 1
    q = 1
    model = sm.tsa.arima.ARIMA(data, order=(p, d, q)).fit()
    ########样本内预测#########
    # in_sample_pred = model.predict()
    # plt.figure()
    # plt.plot(in_sample_pred)
    # plt.plot(data)
    # plt.show()
    ####### 样本外预测##########

    out_sample_pred = model.predict(length, length + daylong, dynamic=True)
    return out_sample_pred
    # plt.figure()
    # plt.plot(data)
    # plt.plot(out_sample_pred)
    # plt.show()
    # plt.figure()
    # plt.plot(data[:1000])
    # plt.plot(results.fittedvalues[:1000],color='red')
    # sm.graphics.tsa.plot_acf(results.resid)
    # sm.graphics.tsa.plot_pacf(results.resid)
    # plt.show()

    # pred_arima= np.zeros(data.shape[0])
    # pred_arima[0] = results.forecast(1)
    # for i in range(1,daylong):
    #     results = results.append([pred_arima[i-1]],refit=False)
    #     pred_arima[i] = results.forecast(1)
    # plt.figure()
    # plt.plot(pred_arima)
    # plt.figure()
    # plt.plot(data_true)
    # plt.show()


# Create your views here.
class OrderViewSet(viewsets.ModelViewSet):
    serializer_class = OrderSerializer
    queryset = Order.objects.all()

    def get_queryset(self):
        queryset = super().get_queryset()
        name = self.request.query_params.get('name', None)
        if name is not None:
            queryset = queryset.filter(name=name)
        return queryset

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # address = serializer.validated_data.pop('address')
        address = request.data.get('address')
        province_id, city_id, district_id = address

        serializer.validated_data['province_id'] = province_id
        serializer.validated_data['city_id'] = city_id
        serializer.validated_data['district_id'] = district_id

        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response({'success': True}, status=status.HTTP_201_CREATED)


class GetProductList(APIView):
    """查询所有订单并通过卡片列表进行展示"""

    def get(self, request):
        orders = Order.objects.all()
        serializer = OrderSerializer(orders, many=True)
        print(serializer.data)
        list = []
        for item in serializer.data:
            created_at = datetime.strptime(item['created_at'], '%Y-%m-%dT%H:%M:%S.%fZ')
            formatted_date = created_at.strftime('%Y-%m-%d')
            status = item['is_complete']
            if status == 1:
                result = "已完成"
            elif status == 2:
                result = "生产中"
            else:
                result = "等待中"
            listdata = {
                "created_at": formatted_date,
                "order_type": item['order'],
                "company": item['company'],
                "name": item['name'],
                "isSetup": True,
                "status": result,
                "note": item['remark']
            }
            list.append(listdata)
        data = {
            "success": True,
            "data": {"list": list}
        }
        return Response(data)


class OrdersCountView(APIView):
    """订单数量"""

    def get(self, request):
        """获取订单总数量、加急订单数量、特殊订单数量"""
        count = Order.objects.all().count()
        urgent_count = Order.objects.filter(order='urgent').count()
        special_count = Order.objects.filter(order='special').count()
        data = {
            'count': count,
            'urgent_count': urgent_count,
            'special_count': special_count
        }
        return Response(data)


class RecentOrdersView(APIView):
    """订单数量"""

    def get(self, request, days):
        """最近几天订单数量,详情"""
        days_ago = timezone.now() - timedelta(days=days)
        print(days_ago)
        orders = Order.objects.filter(created_at__gte=days_ago)
        serializer = OrderSerializer(orders, many=True)
        count = orders.count()
        data = {
            'count': count,
            'data': serializer.data
        }
        return Response(data)


class ordersbyname(APIView):
    """根据订单名称进行分类，画饼状图"""

    def get(self, request):
        """分类"""
        # count = Order.objects.all().count()
        count1 = Order.objects.filter(product_name='Product 1').count()
        count2 = Order.objects.filter(product_name='Product 2').count()
        count3 = Order.objects.filter(product_name='Product 3').count()
        count4 = Order.objects.filter(product_name='Product 4').count()
        list = [
            {"value": count1, "name": 'product1'},
            {"value": count2, "name": 'product2'},
            {"value": count3, "name": 'product3'},
            {"value": count4, "name": 'product4'},
        ]
        data = {
            'product1': count1,
            'product2': count2,
            'product3': count3,
            'product4': count4,
        }
        return Response(list)


class OrdersChartView(APIView):
    """将订单按照时间分类，发送给前端进行图表绘制"""

    def get(self, request):
        """从数据库中读取订单，将同一天的订单数量汇总"""
        orders = Order.objects.annotate(
            date=TruncDate('created_at'),
            order_type=F('order')
        ).values('date', 'order_type').annotate(count=Count('id'), total=Sum('id'))
        order_stats = {}
        for order in orders:
            date = order['date'].strftime('%Y-%m-%d')
            order_type = order['order_type']
            count = order['count']
            # total = order['total']

            if date not in order_stats:
                order_stats[date] = {'total': 0}

            order_stats[date][order_type] = count
            order_stats[date]['total'] += count
            # order_stats[date]['total_amount'] = total
        date_range = Order.objects.all().aggregate(Min('created_at'), Max('created_at'))
        start_date = date_range['created_at__min'].date()
        end_date = date_range['created_at__max'].date()
        for d in range((end_date - start_date).days + 1):
            curr_date = start_date + timedelta(days=d)
            curr_date_str = curr_date.strftime('%Y-%m-%d')
            if curr_date_str not in order_stats:
                order_stats[curr_date_str] = {'total': 0}
        kd = OrderedDict(sorted(order_stats.items(), key=lambda t: t[0]))  # 排序
        date_list = list(kd.keys())
        total_list = [order_stats[date]['total'] if order_stats[date]['total'] else 0 for date in date_list]
        normal_list = [order_stats[date]['normal'] if order_stats[date]['total'] else 0 for date in date_list]
        urgent_list = [
            order_stats[date]['urgent'] if 'urgent' in order_stats[date] and order_stats[date]['total'] else 0 for date
            in
            date_list]
        special_list = [
            order_stats[date]['special'] if 'special' in order_stats[date] and order_stats[date]['total'] else 0 for
            date in
            date_list]
        # pre_data = yuce(7, total_list)
        data = {
            'date_list': date_list,
            'total_list': total_list,
            'normal_list': normal_list,
            'urgent_list': urgent_list,
            'special_list': special_list,
        }

        return Response(data)


class OrdersLineView(APIView):
    """将订单按照时间分类，发送给前端进行图表绘制，增添预测功能，可再次出查询指定天数"""

    def get(self, request, days):
        """从数据库中读取订单，将同一天的订单数量汇总"""
        days_ago = timezone.now() - timedelta(days=days)
        orders = Order.objects.filter(created_at__gte=days_ago).annotate(
            date=TruncDate('created_at'),
            order_type=F('order')
        ).values('date', 'order_type').annotate(count=Count('id'), total=Sum('id'))
        order_stats = {}
        for order in orders:
            date = order['date'].strftime('%Y-%m-%d')
            order_type = order['order_type']
            count = order['count']

            if date not in order_stats:
                order_stats[date] = {'total': 0}

            order_stats[date][order_type] = count
            order_stats[date]['total'] += count
            # order_stats[date]['total_amount'] = total
        now = datetime.now()
        end_date = now
        start_date = now - timedelta(days=days)
        start_date = start_date.replace(hour=0, minute=0, second=0, microsecond=0)
        end_date = end_date.replace(hour=23, minute=59, second=59, microsecond=999999)
        for d in range((end_date - start_date).days):
            curr_date = start_date + timedelta(days=d)
            curr_date_str = curr_date.strftime('%Y-%m-%d')
            print(d, curr_date_str)
            if curr_date_str not in order_stats:
                order_stats[curr_date_str] = {'total': 0}
        kd = OrderedDict(sorted(order_stats.items(), key=lambda t: t[0]))  # 排序
        date_list = list(kd.keys())
        total_list = [order_stats[date]['total'] if order_stats[date]['total'] else 0 for date in date_list]
        normal_list = [order_stats[date]['normal'] if order_stats[date]['total'] else 0 for date in date_list]
        urgent_list = [
            order_stats[date]['urgent'] if 'urgent' in order_stats[date] and order_stats[date]['total'] else 0 for date
            in
            date_list]
        special_list = [
            order_stats[date]['special'] if 'special' in order_stats[date] and order_stats[date]['total'] else 0 for
            date in
            date_list]
        data = {
            'date_list': date_list,
            'total_list': total_list,
            'normal_list': normal_list,
            'urgent_list': urgent_list,
            'special_list': special_list
        }

        return Response(data)


class PredictView(APIView):
    """预测未来七天的订单数量，并进行图表绘制"""

    def get(self, request):
        """从数据库中读取订单，将同一天的订单数量汇总"""
        orders = Order.objects.annotate(
            date=TruncDate('created_at'),
            order_type=F('order')
        ).values('date', 'order_type').annotate(count=Count('id'), total=Sum('id'))
        order_stats = {}
        for order in orders:
            date = order['date'].strftime('%Y-%m-%d')
            order_type = order['order_type']
            count = order['count']
            # total = order['total']

            if date not in order_stats:
                order_stats[date] = {'total': 0}

            order_stats[date][order_type] = count
            order_stats[date]['total'] += count
            # order_stats[date]['total_amount'] = total
        date_range = Order.objects.all().aggregate(Min('created_at'), Max('created_at'))
        start_date = date_range['created_at__min'].date()
        end_date = date_range['created_at__max'].date()
        for d in range((end_date - start_date).days + 1):
            curr_date = start_date + timedelta(days=d)
            curr_date_str = curr_date.strftime('%Y-%m-%d')
            if curr_date_str not in order_stats:
                order_stats[curr_date_str] = {'total': 0}
        kd = OrderedDict(sorted(order_stats.items(), key=lambda t: t[0]))  # 排序
        date_list = list(kd.keys())
        total_list = [order_stats[date]['total'] if order_stats[date]['total'] else 0 for date in date_list]
        # normal_list = [order_stats[date]['normal'] if order_stats[date]['total'] else 0 for date in date_list]
        # urgent_list = [
        #     order_stats[date]['urgent'] if 'urgent' in order_stats[date] and order_stats[date]['total'] else 0 for date
        #     in
        #     date_list]
        # special_list = [
        #     order_stats[date]['special'] if 'special' in order_stats[date] and order_stats[date]['total'] else 0 for
        #     date in
        #     date_list]
        # pre_date =
        now = datetime.now().date()
        end_date = now + timedelta(days=7)
        predate_list = []
        while now <= end_date:
            predate_list.append(now.strftime('%Y-%m-%d'))
            now += timedelta(days=1)
        pre_data = yuce(7, total_list)
        mydata = {}
        tabledata = []
        n=0
        print(predate_list)
        for item in predate_list:
            # print(item)
            mydata['date'] = item,
            mydata['count'] = predate_list[n]
            n = n+1
            tabledata.append(mydata)
        # print(tabledata)
        data = {
            'date_list': date_list,
            'total_list': total_list,
            'pre_data': pre_data,
            'predate_list': predate_list,
            'tabledata': tabledata
        }

        return Response(data)
